package wxb.avalon.core.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import wxb.avalon.core.bean.Result;
import wxb.avalon.core.entity.*;
import wxb.avalon.core.entity.dto.RoomPlayerDto;
import wxb.avalon.core.entity.vo.RoomRoleVo;
import wxb.avalon.core.mapper.RoomMapper;
import wxb.avalon.core.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wxb
 * @since 2022-01-11
 */
@Service
public class RoomServiceImpl extends ServiceImpl<RoomMapper, Room> implements IRoomService {

    @Autowired
    private IRoomPlayerRoleService roomPlayerRoleService;

    @Autowired
    private IPlayerService playerService;

    @Autowired
    private IGamePlayerRoleService gamePlayerRoleService;

    @Autowired
    private IGameService gameService;

    @Autowired
    private IRoomRoleService roomRoleService;

    @Autowired
    private IRoleService roleService;

    @Override
    public Room create(RoomRoleVo vo) {
        Room room = vo.getRoom();
        room.setRoomNo(RandomUtil.randomNumbers(4));
        LambdaQueryWrapper<Room> rq = Wrappers.lambdaQuery();
        rq.eq(Room::getRoomNo, room.getRoomNo());
        List<Room> list = list(rq);
        while (!list.isEmpty()){
            room.setRoomNo(RandomUtil.randomNumbers(4));
            rq.clear();
            rq.eq(Room::getRoomNo, room.getRoomNo());
            list = list(rq);
        }
        save(room);

        List<RoomRole> roomRoles = Lists.newArrayList();
        vo.getRoles().forEach(e->{
            RoomRole roomRole = new RoomRole();
            roomRole.setRoomNo(room.getRoomNo());
            roomRole.setNum(e.getNum());
            roomRole.setRoleId(roleService.getIdByName(e.getName()));
            roomRoles.add(roomRole);
        });

        roomRoleService.saveBatch(roomRoles);


        return room;
    }

    @Override
    public Result<List<RoomPlayerDto>> join(String roomNo, Integer playerId) {
        Result<List<RoomPlayerDto>> result = new Result<>();
        LambdaQueryWrapper<Room> lq = Wrappers.lambdaQuery();
        lq.eq(Room::getRoomNo, roomNo);
        lq.last("limit 1");
        Room room = getOne(lq);
        if (null == room){
            return result.fail("未找到该房间");
        }
        LambdaQueryWrapper<RoomPlayer> rlq = Wrappers.lambdaQuery();
        rlq.eq(RoomPlayer::getRoomNo, roomNo);
        long inPlayers = roomPlayerRoleService.count(rlq);
        if (room.getPlayers() <= inPlayers){
            return result.fail("房间已满");
        }
        RoomPlayer roomPlayer = new RoomPlayer();
        roomPlayer.setPlayerId(playerId);
        roomPlayer.setRoomNo(roomNo);
        roomPlayerRoleService.save(roomPlayer);

        rlq.clear();
        rlq.eq(RoomPlayer::getRoomNo, roomNo);
        rlq.orderByDesc(RoomPlayer::getIdx);
        rlq.last("limit 1");
        RoomPlayer max = roomPlayerRoleService.getOne(rlq);
        if (null == max || null == max.getIdx()){
            max = new RoomPlayer();
            max.setIdx(0);
        }
        roomPlayer.setIdx(max.getIdx() + 1);
        roomPlayerRoleService.updateById(roomPlayer);

        return result.ok(getRoomPlayers(roomNo));
    }

    @Override
    public List<RoomPlayerDto> getRoomPlayers(String roomNo) {
        LambdaQueryWrapper<RoomPlayer> lq = Wrappers.lambdaQuery();
        lq.eq(RoomPlayer::getRoomNo, roomNo);
        List<RoomPlayer> list = roomPlayerRoleService.list(lq);
        return getDtoList(list, roomNo);
    }

    @Override
    public List<RoomPlayerDto> quit(String roomNo, Integer playerId) {
        if (StringUtils.isBlank(roomNo) || null == playerId){
            return Lists.newArrayList();
        }
        LambdaQueryWrapper<RoomPlayer> rq = Wrappers.lambdaQuery();
        rq.eq(RoomPlayer::getRoomNo, roomNo);
        rq.eq(RoomPlayer::getPlayerId, playerId);
        roomPlayerRoleService.remove(rq);

        rq.clear();
        rq.eq(RoomPlayer::getRoomNo, roomNo);
        List<RoomPlayer> list = roomPlayerRoleService.list(rq);
        if (list.isEmpty()){
            LambdaQueryWrapper<Room> rmq = Wrappers.lambdaQuery();
            rmq.eq(Room::getRoomNo, roomNo);
            remove(rmq);
        }

        return getDtoList(list, roomNo);
    }

    @Override
    public Room getByRoomNo(String roomNo) {
        if (StringUtils.isBlank(roomNo)) return null;
        LambdaQueryWrapper<Room> lq = Wrappers.lambdaQuery();
        lq.eq(Room::getRoomNo, roomNo);
        lq.last("limit 1");
        return getOne(lq);
    }

    @Override
    public void createGame(String roomNo, Integer playerId) {
        List<RoomPlayerDto> list = getRoomPlayers(roomNo);
        Integer players = list.stream().findFirst().orElseGet(RoomPlayerDto::new).getPlayers();
        if (null == players || list.size() != players){
            return;
        }
        Game game = new Game();
        game.setRoomNo(roomNo);
        gameService.save(game);
        List<GamePlayerRole> gamePlayerRoles = Lists.newArrayList();
        list.forEach(e->{
            GamePlayerRole gpr = new GamePlayerRole();
            BeanUtils.copyProperties(e, gpr);
            gpr.setId(null);
            gpr.setGameId(game.getId());
            gamePlayerRoles.add(gpr);
        });
        gamePlayerRoleService.saveBatch(gamePlayerRoles);
        allotRoles(gamePlayerRoles);
    }

    @Override
    public void allotRoles(List<GamePlayerRole> list) {
        if (null == list || list.isEmpty()) return;
        String roomNo = list.stream().findFirst().get().getRoomNo();
        List<RoomRole> roomRoles = roomRoleService.getByRoomNo(roomNo);
        List<Integer> roleIds = Lists.newArrayList();
        roomRoles.forEach(e->{
            int i = e.getNum();
            while (i > 0){
                roleIds.add(e.getRoleId());
                i --;
            }
        });
        //乱序
        Collections.shuffle(roleIds);
        for (int i = 0; i < list.size(); i++) {
            list.get(i).setRoleId(roleIds.get(i));
        }
        gamePlayerRoleService.updateBatchById(list);
    }

    private List<RoomPlayerDto> getDtoList(List<RoomPlayer> list, String roomNo){
        List<RoomPlayerDto> roomPlayerDtos = Lists.newArrayList();

        List<Integer> playerIds = list.stream().map(RoomPlayer::getPlayerId).distinct().collect(Collectors.toList());
        List<Player> playerList = playerService.listByIds(playerIds);
        Room room = getByRoomNo(roomNo);
        if (null == room) return roomPlayerDtos;

        for (RoomPlayer roomPlayer : list) {
            RoomPlayerDto dto = new RoomPlayerDto();
            BeanUtils.copyProperties(roomPlayer, dto);
            dto.setName(
                    playerList.stream().filter(e->e.getId().equals(roomPlayer.getPlayerId()))
                            .findFirst().orElseGet(Player::new).getName()
            );
            dto.setPlayers(room.getPlayers());
            roomPlayerDtos.add(dto);
        }
        return roomPlayerDtos;
    }
}
